package com.linhngua.code.gwt.client;

import java.util.Collection;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedStackPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.StackPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import static com.linhngua.code.gwt.client.Constants.*;
public class FunctionGraph implements EntryPoint {

	private RemoteInvocationAsync remoteInvocationAsync = GWT
	.create(RemoteInvocation.class);
	
	private boolean alreadyPrompt;
	
	private Canvas canvas;
	
	private Collection<String> functionList;
	
	private VerticalPanel functionPanel;

	@Override
	public void onModuleLoad() {

		RootPanel rootPanel = RootPanel.get("fg");

		// flextable

		FlexTable flexTable = new FlexTable();
		int row = 0;
		int col = 0;
		// function
		String sampleFunction = "sin(x)";
		flexTable.setWidget(row, col++, new Label("Function"));
		final TextBox functionBox = new TextBox();
		functionBox.setText(sampleFunction);
		flexTable.setWidget(row, col++, functionBox);

		// scale x
		flexTable.setWidget(row, col++, new Label("Scale X"));
		final TextBox scaleXBox = new TextBox();
		double sampleScaleX = 0.01;
		scaleXBox.setText("" + sampleScaleX);
		flexTable.setWidget(row, col++, scaleXBox);

		// scale y
		flexTable.setWidget(row, col++, new Label("Scale Y"));
		double sampleScaleY = 1;
		final TextBox scaleYBox = new TextBox();
		scaleYBox.setText("" + sampleScaleY);
		flexTable.setWidget(row, col++, scaleYBox);

		// button
		Button button = new Button("Draw graph");
		flexTable.setWidget(row, col++, button);
		button.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent clickEvent) {
				String functionText = functionBox.getText();
				double scaleX = Double.parseDouble(scaleXBox.getText());
				double scaleY = Double.parseDouble(scaleYBox.getText());
				functionProcessor(functionText, scaleX, scaleY);
			}
		});

		// canvas
	    canvas = Canvas.createIfSupported();

		canvas.getCanvasElement().setId("canvas");
		canvas.setSize("600px", "600px");
		// layout
		SplitLayoutPanel splitLayoutPanel = new SplitLayoutPanel();
		splitLayoutPanel.setSize("100%", "90%");
		splitLayoutPanel.addNorth(flexTable, 50);
		splitLayoutPanel.add(canvas);
		
		//function list
		functionPanel=new VerticalPanel();
		functionPanel.add(new Label("Available Functions"));
		splitLayoutPanel.addWest(new ScrollPanel(functionPanel), 150);
		rootPanel.add(splitLayoutPanel, 0, 70);
		// start drawing
		functionProcessor(sampleFunction, sampleScaleX, sampleScaleY);

		// handle error

		GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {

			public void onUncaughtException(Throwable t) {
				if (!alreadyPrompt) {
					StringBuilder builder = new StringBuilder();
					for (StackTraceElement e : t.getStackTrace()) {
						builder.append(e.toString());
					}

					Window.prompt("Error", builder.toString());
					alreadyPrompt = true;
				}

			}

		});
		
		
		Timer timer=new Timer() {
			
			@Override
			public void run() {
				refreshRequest();
				
			}
		};
		
		timer.scheduleRepeating(REFRESH_INTERVAL);

		refreshRequest();
	}

	

	protected void refreshRequest() {
		if(functionList==null){
			remoteInvocationAsync.listFunction(new AsyncCallback<Collection<String>>() {
				
				@Override
				public void onSuccess(Collection<String> functions) {
					functionList=functions;
					if(functionList!=null){
						updateFunctionList();
					}
					
				}
				
				@Override
				public void onFailure(Throwable paramThrowable) {
					
					
				}
			});
		}
		
	}



	protected void updateFunctionList() {
		for(String f:functionList){
			functionPanel.add(new Label(f));
		}
		
	}



	public static native void functionProcessor(String functionText,
			double scaleX, double scaleY)/*-{
		$wnd.FunctionProcessor(functionText, scaleX, scaleY);

	}-*/;

}
